@network WEBLOAD NTWRK HEAD='WEB Server Loader', *--------------------------------------------------------------------- * TPNS network definition and scripts to simulate WEB clients. * * The WEB clients request pages of predefined files from a WEB server. * This network can be scaled up with additional simulated clients to * achieve the desired load on the WEB server under test. * * This network and scripts requires TPNS V3R5 or later. *--------------------------------------------------------------------- UTI=0, UTI=0 = no delays BUFSIZE=32767, large receive buffer MLEN=256, limit logging to 256 bytes * STLTRACE=YES, STL trace, use only to * debug scripts OPTIONS=(DEBUG) optional debug flows *--------------------------------------------------------------------- * The pages of files are defined using TPNS UTBL entries. * * Each UTBL entry contains the page name, followed by the log byte, * followed by the file names which make up the page. * * The page name, log byte, and file names are separated using * semicolons (";"). * * The pages defined below are examples of the * Silicon Surf (SM) (Silicon Graphics Inc. Service Mark) model * of WebSTONE (Silicon Graphics Inc. test tool) pages being * defined using TPNS UTBL and UDIST statements. * * * Ex. 0 UTBL (Page 0;)+ Page 0 definition * (0;)+ log byte for page 0 * (/file2k.html.ascii;)+ file 1 * (/file3k.html.ascii), file 2 * (Page 1;)+ Page 1 definition * (1;)+ log byte for page 1 * (/file1k.html.ascii;)+ file 1 * (/file5k.html.ascii), file 2 * (Page 2;)+ Page 2 definition * (2;)+ log byte for page 2 * (/file4k.html.ascii;)+ file 1 * (/file6k.html.ascii), file 2 * (Page 3;)+ Page 3 definition * (3;)+ log byte for page 3 * (/file7k.html.ascii), file 1 * (Page 4;)+ Page 4 definition * (4;)+ log byte for page 4 * (/file8k.html.ascii;)+ file 1 * (/file9k.html.ascii;)+ file 2 * (/file10k.html.ascii;)+ file 3 * (/file11k.html.ascii), file 3 * (Page 5;)+ Page 5 definition * (5;)+ log byte for page 5 * (/file12k.html.ascii;)+ file 1 * (/file14k.html.ascii;)+ file 2 * (/file15k.html.ascii;)+ file 3 * (/file17k.html.ascii;)+ file 4 * (/file18k.html.ascii), file 5 * (Page 6;)+ Page 6 definition * (6;)+ log byte for page 6 * (/file33k.html.ascii), file 1 * (Page 7;)+ Page 7 definition * (7;)+ log byte for page 7 * (/file200k.html.ascii) file 1 * * 0 UDIST 40, 40% for Page 0 * 25, 25% for Page 1 * 15, 15% for Page 2 * 5, 5% for Page 3 * 4, 4% for Page 4 * 4, 4% for Page 5 * 6, 6% for Page 6 * 1 1% for Page 7 * * The following TPNS response time utility (ITPRESP) commands would * be coded to get "page" statistics for the page definitions coded * above. * * BTRANS TYPE=PAGE0,LOG=0,RECORD=XMIT,MATCH=FIRST,TIME=READY * ETRANS LOG=FF,RECORD=RECV,MATCH=LAST,TIME=READY * * BTRANS TYPE=PAGE1,LOG=1,RECORD=XMIT,MATCH=FIRST,TIME=READY * ETRANS LOG=FF,RECORD=RECV,MATCH=LAST,TIME=READY * * BTRANS TYPE=PAGE2,LOG=2,RECORD=XMIT,MATCH=FIRST,TIME=READY * ETRANS LOG=FF,RECORD=RECV,MATCH=LAST,TIME=READY * * BTRANS TYPE=PAGE3,LOG=3,RECORD=XMIT,MATCH=FIRST,TIME=READY * ETRANS LOG=3,RECORD=RECV,MATCH=LAST,TIME=READY * * BTRANS TYPE=PAGE4,LOG=4,RECORD=XMIT,MATCH=FIRST,TIME=READY * ETRANS LOG=FF,RECORD=RECV,MATCH=LAST,TIME=READY * * BTRANS TYPE=PAGE5,LOG=5,RECORD=XMIT,MATCH=FIRST,TIME=READY * ETRANS LOG=FF,RECORD=RECV,MATCH=LAST,TIME=READY * * BTRANS TYPE=PAGE6,LOG=6,RECORD=XMIT,MATCH=FIRST,TIME=READY * ETRANS LOG=6,RECORD=RECV,MATCH=LAST,TIME=READY * * BTRANS TYPE=PAGE7,LOG=7,RECORD=XMIT,MATCH=FIRST,TIME=READY * ETRANS LOG=7,RECORD=RECV,MATCH=LAST,TIME=READY * * RUN * END * *--------------------------------------------------------------------- 0 UTBL (Page 0;)+ Page 0 definition (0;)+ log byte for page 0 (/file2k.html.ascii;)+ file 1 (/file3k.html.ascii), file 2 (Page 1;)+ Page 1 definition (1;)+ log byte for page 1 (/file1k.html.ascii;)+ file 1 (/file5k.html.ascii), file 2 (Page 2;)+ Page 2 definition (2;)+ log byte for page 2 (/file4k.html.ascii;)+ file 1 (/file6k.html.ascii), file 2 (Page 3;)+ Page 3 definition (3;)+ log byte for page 3 (/file7k.html.ascii), file 1 (Page 4;)+ Page 4 definition (4;)+ log byte for page 4 (/file8k.html.ascii;)+ file 1 (/file9k.html.ascii;)+ file 2 (/file10k.html.ascii;)+ file 3 (/file11k.html.ascii), file 3 (Page 5;)+ Page 5 definition (5;)+ log byte for page 5 (/file12k.html.ascii;)+ file 1 (/file14k.html.ascii;)+ file 2 (/file15k.html.ascii;)+ file 3 (/file17k.html.ascii;)+ file 4 (/file18k.html.ascii), file 5 (Page 6;)+ Page 6 definition (6;)+ log byte for page 6 (/file33k.html.ascii), file 1 (Page 7;)+ Page 7 definition (7;)+ log byte for page 7 (/file200k.html.ascii) file 1 *--------------------------------------------------------------------- * The distribution of pages is controlled using TPNS UDIST. *--------------------------------------------------------------------- 0 UDIST 40, 40% for Page 0 25, 25% for Page 1 15, 15% for Page 2 5, 5% for Page 3 4, 4% for Page 4 4, 4% for Page 5 6, 6% for Page 6 1 1% for Page 7 PAGEPATH PATH PAGEDECK path of decks to run *--------------------------------------------------------------------- * The TCPIP statement defines the interface to the IBM TCP/IP product. * SERVADDR=n.n.n.n contains the IP address of the WEB server. *--------------------------------------------------------------------- TCPIP1 TCPIP TYPE=STCP, simple TCP simulation SERVADDR=n.n.n.n, WEB server IP address PATH=(PAGEPATH), path to execute STCPPORT=80 WEB Server port *--------------------------------------------------------------------- * Duplicate the DEV statement with a unique name to define the number * of WEB clients desired. *--------------------------------------------------------------------- WLC00001 DEV WLC00002 DEV WLC00003 DEV WLC00004 DEV WLC00005 DEV WLC00006 DEV WLC00007 DEV WLC00008 DEV WLC00009 DEV WLC00010 DEV WLC00011 DEV WLC00012 DEV WLC00013 DEV WLC00014 DEV WLC00015 DEV WLC00016 DEV WLC00017 DEV WLC00018 DEV WLC00019 DEV WLC00020 DEV WLC00021 DEV WLC00022 DEV WLC00023 DEV WLC00024 DEV WLC00025 DEV @endnetwork /*------------------------------------------------------------------*/ /* STL program to simulate WEB client activities. */ /*------------------------------------------------------------------*/ @program=tpsimwst /*------------------------------------------------------------------*/ /* The following constants allow the STL program to be retranslated */ /* with different page definitions etc. and not require STL code */ /* changes. */ /*------------------------------------------------------------------*/ constant utbl_number 0 /* UTBL number with pages defined*/ constant utbl_dist 'R0' /* UDIST number for distribution */ constant run_time 1*60 /* run time in seconds, either */ /* run time or page_iterations */ /* will stop the simulation run */ constant page_iterations 1000 /* page iterations count */ constant recv_data_timeout 2*60 /* receive timeout in seconds */ constant page_report_time 10 /* page report time in seconds */ constant request_keep_alive 'Y' /* request Keep-Alive on GETs */ constant keep_socket_up 'Y' /* keep socket up */ /* 'Y' = server closes socket */ /* 'N' = client closes socket */ /* after each page received*/ constant debug_messages 'N' /* display script debug messages */ /* set to 'N' once running OK */ /*---------------------------------*/ /* EBCDIC to ASCII translate table */ /*---------------------------------*/ constant ebc2asc '000102031A091A7F1A1A1A0B0C0D0E0F'X||, '101112131A1A081A18191A1A1C1D1E1F'X||, '1A1A1C1A1A0A171B1A1A1A1A1A050607'X||, '1A1A161A1A1E1A041A1A1A1A14151A1A'X||, '20A6E180EB909FE2AB8B9B2E3C282B7C'X||, '26A9AA9CDBA599E3A89E21242A293B5E'X||, '2D2FDFDC9ADDDE989DACBA2C255F3E3F'X||, 'D78894B0B1B2FCD6FB603A2340273D22'X||, 'F861626364656667686996A4F3AFAEC5'X||, '8C6A6B6C6D6E6F7071729787CE93F1FE'X||, 'C87E737475767778797AEFC0DA5BF2F9'X||, 'B5B6FDB7B8B9E6BBBCBD8DD9BF5DD8C4'X||, '7B414243444546474849CBCABEE8ECED'X||, '7D4A4B4C4D4E4F505152A1ADF5F4A38F'X||, '5CE7535455565758595AA0858EE9E4D1'X||, '30313233343536373839B3F7F0FAA7FF'X /*---------------------------------*/ /* ASCII to EBCDIC translate table */ /*---------------------------------*/ constant asc2ebc '00010203372D2E2F1605250B0C0D0E0F'X||, '101112133C3D322618193F27221D351F'X||, '405A7F7B5B6C507D4D5D5C4E6B604B61'X||, 'F0F1F2F3F4F5F6F7F8F97A5E4C7E6E6F'X||, '7CC1C2C3C4C5C6C7C8C9D1D2D3D4D5D6'X||, 'D7D8D9E2E3E4E5E6E7E8E9ADE0BD5F6D'X||, '79818283848586878889919293949596'X||, '979899A2A3A4A5A6A7A8A9C04FD0A107'X||, '00010203372D2E2F1605250B0C0D0E0F'X||, '101112133C3D322618193F27221D351F'X||, '405A7F7B5B6C507D4D5D5C4E6B604B61'X||, 'F0F1F2F3F4F5F6F7F8F97A5E4C7E6E6F'X||, '7CC1C2C3C4C5C6C7C8C9D1D2D3D4D5D6'X||, 'D7D8D9E2E3E4E5E6E7E8E9ADE0BD5F6D'X||, '79818283848586878889919293949596'X||, '979899A2A3A4A5A6A7A8A9C04FD0A107'X constant crlf '0D25'x /* CR/LF in EBCDIC */ constant end_page_log_byte 'FF'x /* end page log byte */ constant recv_timeout_event 'TIMEOUT' /* timeout event name */ constant file_complete_event 'GO' /* continue event name */ constant run_time_event 'RUNTIME' /* run time event name */ constant kill_run_time_event 'KILRUNTM' /* kill run time event */ constant reporter_event 'REPORTER' /* reporter event name */ constant kill_reporter_event 'KILREPRT' /* kill reporter event */ integer shared active_clients /* active clients */ integer shared total_clients /* total clients */ integer shared total_pages_received /* total pages received*/ integer shared pages_received_report /* pages recv to report*/ string shared connection_header PAGEDECK: msgtxt /*------------------------------------------------------------------*/ /* This script selects a page of files from the UTBL and issues a */ /* GET request for each file associated with the page. */ /*------------------------------------------------------------------*/ if total_clients = 0 then do connection_header = '' client_closes_socket = on if request_keep_alive = 'Y' then do connection_header = 'Connection: Keep-Alive'||crlf if keep_socket_up = 'Y' then client_closes_socket = off end say 'The maximum run time is' char(run_time) 'seconds.' say 'Active Options:' say ' Request_Keep_Alive =' request_keep_alive if request_keep_alive = 'Y' then say ' Keep_Socket_Up =' keep_socket_up say 'The page report time is' char(page_report_time) 'seconds.' say '----------', tod(2)':'right(tod(4),2)':'right(tod(6),2)'.'right(tod(),2), '----------' qsignal run_time_event after run_time reset run_time_event on signaled(run_time_event) then do say '+-------------------------------------+' say '| The run time has expired, |' say '| simulated clients will be stopping. |' say '+-------------------------------------+' post run_time_event end on signaled(kill_run_time_event) then cancel run_time_event /*------------------------------------*/ /* Setup the reporter event and timer */ /*------------------------------------*/ qsignal reporter_event after page_report_time on signaled(reporter_event) then execute reporter on signaled(kill_reporter_event) then cancel reporter_event end active_clients = active_clients + 1 total_clients = total_clients + 1 /*------------------------------------------------------------------*/ /* The following loop controls how many pages will be accessed by */ /* each WEB client. */ /*------------------------------------------------------------------*/ loop_counter = 1 do while loop_counter <= page_iterations & posted(run_time_event) = off /*-------------------------------------------------------------*/ /* Pick up a new page of files definition from TPNS UTBL entry */ /*-------------------------------------------------------------*/ page_files = utbl(utbl_number,utbl_dist) /*-------------------*/ /* Pick up page name */ /*-------------------*/ semi_index = index(page_files,';') if semi_index > 0 then do page_name = left(page_files,semi_index-1) if length(page_name) > 8 then do say 'WARNING: Page name' page_name 'truncated to 8 bytes.' page_name = left(page_name,8) end semi_index = semi_index + 1 if semi_index = length(page_files) then do page_files = '' say 'ERROR: No log byte defined for page' page_name'.' quiesce end else page_files = substr(page_files,semi_index) /*------------------*/ /* Pick up log byte */ /*------------------*/ semi_index = index(page_files,';') if semi_index > 0 then do log_byte = left(page_files,semi_index-1) if length(log_byte) > 1 then do say 'WARNING: Log byte' log_byte 'truncated to 1 byte.' log_byte = left(log_byte,1) end semi_index = semi_index + 1 if semi_index = length(page_files) then do page_files = '' say 'ERROR: No files defined for page' page_name'.' quiesce end else page_files = substr(page_files,semi_index) if debug_messages = 'Y' then say page_name end else do say 'ERROR: Log byte not found in UTBL definition.' quiesce end end else do say 'ERROR: Page name not found in UTBL definition.' quiesce end suspend(0) /* force a refresh of the TOD value */ /*----------------------------------------------------*/ /* Issue a GET for each file associated with the page */ /*----------------------------------------------------*/ first_file_in_page_sw = on last_file_in_page_sw = off socket_open_sw = off do while length(page_files) > 0 semi_index = index(page_files,';') if semi_index > 0 then do file_name = left(page_files,semi_index-1) semi_index = semi_index + 1 if semi_index = length(page_files) then page_files = '' else page_files = substr(page_files,semi_index) end else do file_name = page_files page_files = '' end /*----------------------------------------------------------*/ /* Set end-of-page log byte for response time utility usage */ /*----------------------------------------------------------*/ if page_files = '' then do if first_file_in_page_sw = off then log_byte = end_page_log_byte last_file_in_page_sw = on end /*----------------------------------*/ /* GET the file from the WEB server */ /*----------------------------------*/ get_file_error_sw = on do while get_file_error_sw = on call GETFILE if get_file_error_sw = on then say 'RETRY:' page_name file_name end first_file_in_page_sw = off end loop_counter = loop_counter + 1 pages_received_report = pages_received_report + 1 end /*--------------------------------------*/ /* Close the socket if it is still open */ /*--------------------------------------*/ if socket_open_sw = on then do /*---------------------------------------*/ /* Close socket via sending null message */ /*---------------------------------------*/ socket_open_sw = off type '' delay(0) transmit end /*-------------------------------------------------------------*/ /* Stop TPNS from opening any more sockets for this WEB client */ /*-------------------------------------------------------------*/ active_clients = active_clients - 1 if debug_messages = 'Y' then say 'Test completed, time to quiesce' if active_clients = 0 then do signal kill_reporter_event signal kill_run_time_event say '+-------------------------------------------+' say '| Test completed for all simulated clients. |' say '+-------------------------------------------+' say 'Total clients simulated:' char(total_clients) total_pages_received = total_pages_received + pages_received_report say 'Total pages received: ' char(total_pages_received) total_clients = 0 total_pages_received = 0 end quiesce endtxt GETFILE: msgtxt /*------------------------------------------------------------------*/ /* This routine issues the HTTP GET request for a file. */ /* Receive data timeouts, status code 200 verification, and */ /* Content-Length: nnnn file data received are handled here. */ /*------------------------------------------------------------------*/ first_msg = '' input_msg_leng = 0 total_msg_leng = 0 time_out_sw = off keep_alive_active_sw = off /*-----------------------------------------------------------*/ /* Setup up the TPNS event timer and onins for the file data */ /* received after the HTTP GET is issued */ /*-----------------------------------------------------------*/ /*------------------------------------*/ /* Give up waiting for file data when */ /* the receive data timeout expires */ /*------------------------------------*/ qsignal recv_timeout_event after recv_data_timeout on signaled(recv_timeout_event) then do time_out_sw = on qsignal file_complete_event end /*---------------------------------------------------------------*/ /* Update the data received counts and restart the timeout timer */ /*---------------------------------------------------------------*/ msgin1: onin then do input_msg_leng = length(data) total_msg_leng = total_msg_leng + input_msg_leng cancel recv_timeout_event qsignal recv_timeout_event after recv_data_timeout end /*----------------------------------------*/ /* Save the first packet of data received */ /*----------------------------------------*/ msgin2: onin input_msg_leng > 0 then do first_msg = substr(data,1,512) qsignal file_complete_event deact msgin2 end /*----------------------------------------------*/ /* Continue message generation process when the */ /* socket is closed */ /*----------------------------------------------*/ msgin3: onin input_msg_leng = 0 then do socket_open_sw = off qsignal file_complete_event end /*-------------------------------------------------*/ /* Send the HTTP GET request for the file and wait */ /* for either a timeout or closing of the socket */ /*-------------------------------------------------*/ type translate('GET '||file_name||' HTTP/1.0'||crlf||, connection_header||, 'Accept: */* HTTP/1.0'||crlf||, crlf,ebc2asc) socket_open_sw = on if debug_messages = 'Y' then say 'GET' file_name delay(0) /* make sure we can get back into msg gen quickly */ transmit logging log_byte and wait until signaled(file_complete_event) /*----------------------------------------------*/ /* Cancel the outstanding event timer and onins */ /*----------------------------------------------*/ cancel recv_timeout_event deact msgin1, msgin2, msgin3 /*---------------------------------*/ /* Check for a valid file transfer */ /*---------------------------------*/ select /*----------------------*/ /* Receive data timeout */ /*----------------------*/ when time_out_sw = on then do say 'ERROR: File transfer time out after' char(total_msg_leng), 'bytes received.' /*---------------------------------------*/ /* Close socket via sending null message */ /*---------------------------------------*/ socket_open_sw = off type '' delay(0) /* make sure we can get back into msg gen quickly */ transmit logging log_byte end /*------------------------------------------*/ /* Socket closed without receiving any data */ /*------------------------------------------*/ when total_msg_leng = 0 then say 'ERROR: Socket closed without receiving any data.' /*---------------------------------------*/ /* Some file data received, check it out */ /*---------------------------------------*/ otherwise do /*---------------------------------------------------*/ /* Translate first packet of data received to EBCDIC */ /*---------------------------------------------------*/ first_msg = translate(first_msg,asc2ebc) /*-----------------------------------------------*/ /* Check for "HTTP/1.n 200" status code received */ /*-----------------------------------------------*/ end_header_index = index(first_msg,crlf||crlf) select when end_header_index = 0 then say 'ERROR: Unable to find end of HTTP header.' when left(first_msg,5) <> 'HTTP/' then say 'ERROR: Unable to find beginning of HTTP header.' otherwise do space_index = index(first_msg,' ') select when space_index = 0 then say 'ERROR: HTTP status code delimiter not found.' when substr(first_msg,space_index,4) <> ' 200' then do say 'ERROR: Incorrect status code received' say ' Expected 200 Received', substr(first_msg,space_index+1,3) end /*------------------------------------------------------*/ /* Status code OK, now check for all file data received */ /*------------------------------------------------------*/ otherwise do if index(first_msg,'Connection: Keep-Alive') > 0 then keep_alive_active_sw = on cl_index = index(first_msg,'Content-Length: ') if cl_index = 0 then say 'ERROR: "Content_Length: nnnn" not found.' else do content_leng = e2d(substr(first_msg,cl_index+16)) file_header_size = end_header_index + 3 test_msg_leng = content_leng + file_header_size if socket_open_sw = on then do if keep_alive_active_sw = off |, total_msg_leng < test_msg_leng then do qsignal recv_timeout_event after recv_data_timeout /*-------------------------------------*/ /* Update the data received counts and */ /* restart the timeout timer */ /*-------------------------------------*/ msgin4: onin then do input_msg_leng = length(data) total_msg_leng = total_msg_leng + input_msg_leng cancel recv_timeout_event qsignal recv_timeout_event after recv_data_timeout end if keep_alive_active_sw = on then do /*----------------------------------------------*/ /* Continue message generation process when the */ /* complete file data is received */ /*----------------------------------------------*/ msgin5: onin total_msg_leng >= test_msg_leng then qsignal file_complete_event end /*----------------------------------------------*/ /* Continue message generation process when the */ /* socket is closed */ /*----------------------------------------------*/ msgin6: onin input_msg_leng = 0 then do socket_open_sw = off qsignal file_complete_event end delay(0) wait until signaled(file_complete_event) cancel recv_timeout_event deact msgin4, msgin5, msgin6 end if time_out_sw = on |, (socket_open_sw = on &, keep_alive_active_sw = on &, last_file_in_page_sw = on &, client_closes_socket = on) then do /*---------------------------------------*/ /* Close socket via sending null message */ /*---------------------------------------*/ socket_open_sw = off type '' delay(0) transmit logging log_byte end end if time_out_sw = on then say 'ERROR: File transfer time out after', char(total_msg_leng) 'bytes received.' else do file_body_size = total_msg_leng - file_header_size /*-----------------------------------*/ /* Total file received without error */ /*-----------------------------------*/ if file_body_size = content_leng then get_file_error_sw = off /*--------------------------*/ /* Total file not received? */ /*--------------------------*/ else do say 'ERROR: Incorrect number of file bytes received.' say ' Expected' char(content_leng), 'Received' char(file_body_size) end end end end end end end end end endtxt REPORTER: msgtxt /*---------------------------*/ /* Generate an online report */ /*---------------------------*/ say '----------', tod(2)':'right(tod(4),2)':'right(tod(6),2)'.'right(tod(),2), '----------' say 'Pages received since last report:', char(pages_received_report) total_pages_received = total_pages_received + pages_received_report pages_received_report = 0 say 'Total pages received: ', char(total_pages_received) qsignal reporter_event after page_report_time on signaled(reporter_event) then execute reporter endtxt